package server

import (
	"net/http"
	"strings"
	"sync"
)

type FILTER_RESULT int

const BREAK FILTER_RESULT = 0
const CONTINUE FILTER_RESULT = 1
const FLYUP FILTER_RESULT = 2

type HandlerFilter interface {
	ServeHTTP(http.ResponseWriter, *http.Request) FILTER_RESULT
}

type HandlerFilterFunc func(http.ResponseWriter, *http.Request) FILTER_RESULT

func (h HandlerFilterFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) FILTER_RESULT {
	return h(w, r)
}

type Filter struct {
	h       HandlerFilter
	pattern string
}

type ServerFilter struct {
	id     string
	wmutx  sync.RWMutex
	filter map[string]Filter
}

func NewServerFilter(id string) *ServerFilter {
	return &ServerFilter{
		id:     id,
		filter: make(map[string]Filter),
	}
}
func (sf *ServerFilter) GetId() string {
	return sf.id
}

func (sf *ServerFilter) lock() {
	sf.wmutx.Lock()
}
func (sf *ServerFilter) unLock() {
	sf.wmutx.Unlock()
}

func (sf *ServerFilter) Filter(pattern string, handler HandlerFilter) {
	sf.lock()
	defer sf.unLock()

	if pattern == "" {
		panic("http: invalid pattern")
	}
	if _, exist := sf.filter[pattern]; exist {
		panic("http: multiple registrations for " + pattern)
	}

	if sf.filter == nil {
		sf.filter = make(map[string]Filter)
	}
	sf.filter[pattern] = Filter{
		pattern: pattern,
		h:       handler,
	}
}

func (sf *ServerFilter) FilterFunc(pattern string, handler func(http.ResponseWriter, *http.Request) FILTER_RESULT) {
	sf.Filter(pattern, HandlerFilterFunc(handler))
}

type ServerMux struct {
	*http.ServeMux
	wmutx      sync.RWMutex
	filters    map[string]ServerFilter
	filterSort []string
}

func NewServeMux() *ServerMux {
	mux := &ServerMux{
		ServeMux:   http.NewServeMux(),
		filterSort: []string{},
		filters:    make(map[string]ServerFilter),
	}
	return mux
}

func (mux *ServerMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	flag := mux.filterMatch93(r.URL.Path, w, r)
	switch flag {
	case FLYUP, CONTINUE:
		mux.ServeMux.ServeHTTP(w, r)
		return
	case BREAK:
		return
	}
}

func (mux *ServerMux) filterMatch93(path string, w http.ResponseWriter, r *http.Request) FILTER_RESULT {
	for _, v := range mux.filterSort {
		if filter, ok := mux.filters[v].filter[path]; ok { //存在
			flag := filter.h.ServeHTTP(w, r)
			switch flag {
			case FLYUP, BREAK:
				return flag
			}

		}
	}
	return CONTINUE
}

func (mux *ServerMux) AddFilter(id string, sf *ServerFilter) {
	mux.wmutx.Lock()
	defer mux.wmutx.Unlock()
	mux.filterSort = append(mux.filterSort, id)
	mux.filters[id] = (*sf)
}

func (mux *ServerMux) RemoveFilter(id string) {
	mux.wmutx.Lock()
	defer mux.wmutx.Unlock()
	delete(mux.filters, id)

	for i := 0; i < len(mux.filterSort); i++ {
		if strings.Compare(mux.filterSort[i], id) == 0 {
			mux.filterSort = append(mux.filterSort[:i], mux.filterSort[i+1:]...)
			i--
		}
	}
}

func EmptyContinueHandlerFilter(http.ResponseWriter, *http.Request) FILTER_RESULT {
	return CONTINUE
}

func EmptyBreakHandlerFilter(http.ResponseWriter, *http.Request) FILTER_RESULT {
	return BREAK
}

func EmptyFlyUpHandlerFilter(http.ResponseWriter, *http.Request) FILTER_RESULT {
	return FLYUP
}
